﻿' Source: http://www.vbaccelerator.com/home/NET/Code/Libraries/Shell_Projects/SysImageList/article.asp

Imports System.Drawing
Imports System.Runtime.InteropServices
Imports System.Windows.Forms


#Region "Public Enumerations"
''' <summary>
''' Available system image list sizes
''' </summary>
Public Enum SystemImageListSize As Integer
    ''' <summary>
    ''' System Large Icon Size (typically 32x32)
    ''' </summary>
    LargeIcons = &H0
    ''' <summary>
    ''' System Small Icon Size (typically 16x16)
    ''' </summary>
    SmallIcons = &H1
    ''' <summary>
    ''' System Extra Large Icon Size (typically 48x48).
    ''' Only available under XP; under other OS the
    ''' Large Icon ImageList is returned.
    ''' </summary>
    ExtraLargeIcons = &H2
End Enum

''' <summary>
''' Flags controlling how the Image List item is 
''' drawn
''' </summary>
<Flags()> _
Public Enum ImageListDrawItemConstants As Integer
    ''' <summary>
    ''' Draw item normally.
    ''' </summary>
    ILD_NORMAL = &H0
    ''' <summary>
    ''' Draw item transparently.
    ''' </summary>
    ILD_TRANSPARENT = &H1
    ''' <summary>
    ''' Draw item blended with 25% of the specified foreground colour
    ''' or the Highlight colour if no foreground colour specified.
    ''' </summary>
    ILD_BLEND25 = &H2
    ''' <summary>
    ''' Draw item blended with 50% of the specified foreground colour
    ''' or the Highlight colour if no foreground colour specified.
    ''' </summary>
    ILD_SELECTED = &H4
    ''' <summary>
    ''' Draw the icon's mask
    ''' </summary>
    ILD_MASK = &H10
    ''' <summary>
    ''' Draw the icon image without using the mask
    ''' </summary>
    ILD_IMAGE = &H20
    ''' <summary>
    ''' Draw the icon using the ROP specified.
    ''' </summary>
    ILD_ROP = &H40
    ''' <summary>
    ''' Preserves the alpha channel in dest. XP only.
    ''' </summary>
    ILD_PRESERVEALPHA = &H1000
    ''' <summary>
    ''' Scale the image to cx, cy instead of clipping it.  XP only.
    ''' </summary>
    ILD_SCALE = &H2000
    ''' <summary>
    ''' Scale the image to the current DPI of the display. XP only.
    ''' </summary>
    ILD_DPISCALE = &H4000
End Enum

''' <summary>
''' Enumeration containing XP ImageList Draw State options
''' </summary>
<Flags()> _
Public Enum ImageListDrawStateConstants As Integer
    ''' <summary>
    ''' The image state is not modified. 
    ''' </summary>
    ILS_NORMAL = (&H0)
    ''' <summary>
    ''' Adds a glow effect to the icon, which causes the icon to appear to glow 
    ''' with a given color around the edges. (Note: does not appear to be
    ''' implemented)
    ''' </summary>
    ILS_GLOW = (&H1)
    'The color for the glow effect is passed to the IImageList::Draw method in the crEffect member of IMAGELISTDRAWPARAMS. 
    ''' <summary>
    ''' Adds a drop shadow effect to the icon. (Note: does not appear to be
    ''' implemented)
    ''' </summary>
    ILS_SHADOW = (&H2)
    'The color for the drop shadow effect is passed to the IImageList::Draw method in the crEffect member of IMAGELISTDRAWPARAMS. 
    ''' <summary>
    ''' Saturates the icon by increasing each color component 
    ''' of the RGB triplet for each pixel in the icon. (Note: only ever appears
    ''' to result in a completely unsaturated icon)
    ''' </summary>
    ILS_SATURATE = (&H4)
    ' The amount to increase is indicated by the frame member in the IMAGELISTDRAWPARAMS method. 
    ''' <summary>
    ''' Alpha blends the icon. Alpha blending controls the transparency 
    ''' level of an icon, according to the value of its alpha channel. 
    ''' (Note: does not appear to be implemented).
    ''' </summary>
    ILS_ALPHA = (&H8)
    'The value of the alpha channel is indicated by the frame member in the IMAGELISTDRAWPARAMS method. The alpha channel can be from 0 to 255, with 0 being completely transparent, and 255 being completely opaque. 
End Enum

''' <summary>
''' Flags specifying the state of the icon to draw from the Shell
''' </summary>
<Flags()> _
Public Enum ShellIconStateConstants
    ''' <summary>
    ''' Get icon in normal state
    ''' </summary>
    ShellIconStateNormal = 0
    ''' <summary>
    ''' Put a link overlay on icon 
    ''' </summary>
    ShellIconStateLinkOverlay = &H8000
    ''' <summary>
    ''' show icon in selected state 
    ''' </summary>
    ShellIconStateSelected = &H10000
    ''' <summary>
    ''' get open icon 
    ''' </summary>
    ShellIconStateOpen = &H2
    ''' <summary>
    ''' apply the appropriate overlays
    ''' </summary>
    ShellIconAddOverlays = &H20
End Enum
#End Region

#Region "SystemImageList class"
''' <summary>
''' Summary description for SysImageList.
''' </summary>
Public Class SystemImageList
    Implements IDisposable
#Region "Constants"
    Private Const MAX_PATH As Integer = 260

    Private Const FILE_ATTRIBUTE_NORMAL As Integer = &H80
    Private Const FILE_ATTRIBUTE_DIRECTORY As Integer = &H10

    Private Const FORMAT_MESSAGE_ALLOCATE_BUFFER As Integer = &H100
    Private Const FORMAT_MESSAGE_ARGUMENT_ARRAY As Integer = &H2000
    Private Const FORMAT_MESSAGE_FROM_HMODULE As Integer = &H800
    Private Const FORMAT_MESSAGE_FROM_STRING As Integer = &H400
    Private Const FORMAT_MESSAGE_FROM_SYSTEM As Integer = &H1000
    Private Const FORMAT_MESSAGE_IGNORE_INSERTS As Integer = &H200
    Private Const FORMAT_MESSAGE_MAX_WIDTH_MASK As Integer = &HFF
#End Region

#Region "Fields"
    Private hIml As IntPtr = IntPtr.Zero
    Private kiImageList As IImageList = Nothing
    Private m_size As SystemImageListSize = SystemImageListSize.SmallIcons
    Private disposed As Boolean = False
#End Region

#Region "Private Enumerations"
    <Flags()> _
    Private Enum SHGetFileInfoConstants As Integer
        SHGFI_ICON = &H100
        ' get icon 
        SHGFI_DISPLAYNAME = &H200
        ' get display name 
        SHGFI_TYPENAME = &H400
        ' get type name 
        SHGFI_ATTRIBUTES = &H800
        ' get attributes 
        SHGFI_ICONLOCATION = &H1000
        ' get icon location 
        SHGFI_EXETYPE = &H2000
        ' return exe type 
        SHGFI_SYSICONINDEX = &H4000
        ' get system icon index 
        SHGFI_LINKOVERLAY = &H8000
        ' put a link overlay on icon 
        SHGFI_SELECTED = &H10000
        ' show icon in selected state 
        SHGFI_ATTR_SPECIFIED = &H20000
        ' get only specified attributes 
        SHGFI_LARGEICON = &H0
        ' get large icon 
        SHGFI_SMALLICON = &H1
        ' get small icon 
        SHGFI_OPENICON = &H2
        ' get open icon 
        SHGFI_SHELLICONSIZE = &H4
        ' get shell size icon 
        'SHGFI_PIDL = 0x8,                  // pszPath is a pidl 
        SHGFI_USEFILEATTRIBUTES = &H10
        ' use passed dwFileAttribute 
        SHGFI_ADDOVERLAYS = &H20
        ' apply the appropriate overlays
        SHGFI_OVERLAYINDEX = &H40
        ' Get the index of the overlay
    End Enum
#End Region

#Region "Private ImageList structures"
    <StructLayout(LayoutKind.Sequential)> _
    Private Structure RECT
        Private left As Integer
        Private top As Integer
        Private right As Integer
        Private bottom As Integer
    End Structure

    <StructLayout(LayoutKind.Sequential)> _
    Private Structure POINT
        Private x As Integer
        Private y As Integer
    End Structure

    <StructLayout(LayoutKind.Sequential)> _
    Private Structure IMAGELISTDRAWPARAMS
        Public cbSize As Integer
        Public himl As IntPtr
        Public i As Integer
        Public hdcDst As IntPtr
        Public x As Integer
        Public y As Integer
        Public cx As Integer
        Public cy As Integer
        Public xBitmap As Integer
        ' x offest from the upperleft of bitmap
        Public yBitmap As Integer
        ' y offset from the upperleft of bitmap
        Public rgbBk As Integer
        Public rgbFg As Integer
        Public fStyle As Integer
        Public dwRop As Integer
        Public fState As Integer
        Public Frame As Integer
        Public crEffect As Integer
    End Structure

    <StructLayout(LayoutKind.Sequential)> _
    Private Structure IMAGEINFO
        Public hbmImage As IntPtr
        Public hbmMask As IntPtr
        Public Unused1 As Integer
        Public Unused2 As Integer
        Public rcImage As RECT
    End Structure
    <StructLayout(LayoutKind.Sequential)> _
    Private Structure SHFILEINFO
        Public hIcon As IntPtr
        Public iIcon As Integer
        Public dwAttributes As Integer
        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=MAX_PATH)> _
        Public szDisplayName As String
        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=80)> _
        Public szTypeName As String
    End Structure
#End Region

#Region "Constructors, Dispose, Destructor"
    ''' <summary>
    ''' Creates a Small Icons SystemImageList 
    ''' </summary>
    Public Sub New()
        create()
    End Sub
    ''' <summary>
    ''' Creates a SystemImageList with the specified size
    ''' </summary>
    ''' <param name="size">Size of System ImageList</param>
    Public Sub New(ByVal size As SystemImageListSize)
        Me.m_size = size
        create()
    End Sub

    ''' <summary>
    ''' Clears up any resources associated with the SystemImageList
    ''' </summary>
    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
    ''' <summary>
    ''' Clears up any resources associated with the SystemImageList
    ''' when disposing is true.
    ''' </summary>
    ''' <param name="disposing">Whether the object is being disposed</param>
    Public Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not disposed Then
            If disposing Then
                If kiImageList IsNot Nothing Then
                    Marshal.ReleaseComObject(kiImageList)
                End If
                kiImageList = Nothing
            End If
        End If
        disposed = True
    End Sub
    ''' <summary>
    ''' Finalise for SysImageList
    ''' </summary>
    Protected Overrides Sub Finalize()
        Try
            Dispose(False)
        Finally
            MyBase.Finalize()
        End Try
    End Sub
#End Region

#Region "Implementation"

    <DllImport("shell32")> _
    Private Shared Function SHGetFileInfo(ByVal pszPath As String, ByVal dwFileAttributes As Integer, ByRef psfi As SHFILEINFO, ByVal cbFileInfo As UInteger, ByVal uFlags As UInteger) As IntPtr
    End Function

    <DllImport("user32.dll")> _
    Private Shared Function DestroyIcon(ByVal hIcon As IntPtr) As Integer
    End Function

    <DllImport("kernel32")> _
    Private Shared Function FormatMessage(ByVal dwFlags As Integer, ByVal lpSource As IntPtr, ByVal dwMessageId As Integer, ByVal dwLanguageId As Integer, ByVal lpBuffer As String, ByVal nSize As UInteger, _
     ByVal argumentsLong As Integer) As Integer
    End Function

    <DllImport("kernel32")> _
    Private Shared Function GetLastError() As Integer
    End Function

    <DllImport("comctl32")> _
    Private Shared Function ImageList_Draw(ByVal hIml As IntPtr, ByVal i As Integer, ByVal hdcDst As IntPtr, ByVal x As Integer, ByVal y As Integer, ByVal fStyle As Integer) As Integer
    End Function

    <DllImport("comctl32")> _
    Private Shared Function ImageList_DrawIndirect(ByRef pimldp As IMAGELISTDRAWPARAMS) As Integer
    End Function

    <DllImport("comctl32")> _
    Private Shared Function ImageList_GetIconSize(ByVal himl As IntPtr, ByRef cx As Integer, ByRef cy As Integer) As Integer
    End Function

    <DllImport("comctl32")> _
    Private Shared Function ImageList_GetIcon(ByVal himl As IntPtr, ByVal i As Integer, ByVal flags As Integer) As IntPtr
    End Function

    ''' <summary>
    ''' SHGetImageList is not exported correctly in XP.  See KB316931
    ''' http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q316931
    ''' Apparently (and hopefully) ordinal 727 isn't going to change.
    ''' </summary>
    <DllImport("shell32.dll", EntryPoint:="#727")> _
    Private Shared Function SHGetImageList(ByVal iImageList As Integer, ByRef riid As Guid, ByRef ppv As IImageList) As Integer
    End Function

    <DllImport("shell32.dll", EntryPoint:="#727")> _
    Private Shared Function SHGetImageListHandle(ByVal iImageList As Integer, ByRef riid As Guid, ByRef handle As IntPtr) As Integer
    End Function

    ''' <summary>
    ''' Determines if the system is running Windows XP
    ''' or above
    ''' </summary>
    ''' <returns>True if system is running XP or above, False otherwise</returns>
    Private Function isXpOrAbove() As Boolean
        Dim ret As Boolean = False
        If Environment.OSVersion.Version.Major > 5 Then
            ret = True
        ElseIf (Environment.OSVersion.Version.Major = 5) AndAlso (Environment.OSVersion.Version.Minor >= 1) Then
            ret = True
        End If
        Return ret
        'return false;
    End Function

    ''' <summary>
    ''' Creates the SystemImageList
    ''' </summary>
    Private Sub create()
        ' forget last image list if any:
        hIml = IntPtr.Zero

        If isXpOrAbove() Then
            ' Get the System IImageList object from the Shell:
            Dim iidImageList As New Guid("46EB5926-582E-4017-9FDF-E8998DAA0950")
            Dim ret As Integer = SHGetImageList(CInt(m_size), iidImageList, kiImageList)
            ' the image list handle is the IUnknown pointer, but 
            ' using Marshal.GetIUnknownForObject doesn't return
            ' the right value.  It really doesn't hurt to make
            ' a second call to get the handle:
            SHGetImageListHandle(CInt(m_size), iidImageList, hIml)
        Else
            ' Prepare flags:
            Dim dwFlags As SHGetFileInfoConstants = SHGetFileInfoConstants.SHGFI_USEFILEATTRIBUTES Or SHGetFileInfoConstants.SHGFI_SYSICONINDEX
            If m_size = SystemImageListSize.SmallIcons Then
                dwFlags = dwFlags Or SHGetFileInfoConstants.SHGFI_SMALLICON
            End If
            ' Get image list
            Dim shfi As New SHFILEINFO()
            Dim shfiSize As UInteger = CUInt(Marshal.SizeOf(shfi.[GetType]()))

            ' Call SHGetFileInfo to get the image list handle
            ' using an arbitrary file:
            hIml = SHGetFileInfo(".txt", FILE_ATTRIBUTE_NORMAL, shfi, shfiSize, CUInt(dwFlags))
            System.Diagnostics.Debug.Assert((hIml <> IntPtr.Zero), "Failed to create Image List")
        End If
    End Sub

#Region "Private ImageList COM Interop (XP)"
    'helpstring("Image List"),
    <ComImportAttribute()> _
    <GuidAttribute("46EB5926-582E-4017-9FDF-E8998DAA0950")> _
    <InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)> _
    Private Interface IImageList
        <PreserveSig()> _
        Function Add(ByVal hbmImage As IntPtr, ByVal hbmMask As IntPtr, ByRef pi As Integer) As Integer

        <PreserveSig()> _
        Function ReplaceIcon(ByVal i As Integer, ByVal hicon As IntPtr, ByRef pi As Integer) As Integer

        <PreserveSig()> _
        Function SetOverlayImage(ByVal iImage As Integer, ByVal iOverlay As Integer) As Integer

        <PreserveSig()> _
        Function Replace(ByVal i As Integer, ByVal hbmImage As IntPtr, ByVal hbmMask As IntPtr) As Integer

        <PreserveSig()> _
        Function AddMasked(ByVal hbmImage As IntPtr, ByVal crMask As Integer, ByRef pi As Integer) As Integer

        <PreserveSig()> _
        Function Draw(ByRef pimldp As IMAGELISTDRAWPARAMS) As Integer

        <PreserveSig()> _
        Function Remove(ByVal i As Integer) As Integer

        <PreserveSig()> _
        Function GetIcon(ByVal i As Integer, ByVal flags As Integer, ByRef picon As IntPtr) As Integer

        <PreserveSig()> _
        Function GetImageInfo(ByVal i As Integer, ByRef pImageInfo As IMAGEINFO) As Integer

        <PreserveSig()> _
        Function Copy(ByVal iDst As Integer, ByVal punkSrc As IImageList, ByVal iSrc As Integer, ByVal uFlags As Integer) As Integer

        <PreserveSig()> _
        Function Merge(ByVal i1 As Integer, ByVal punk2 As IImageList, ByVal i2 As Integer, ByVal dx As Integer, ByVal dy As Integer, ByRef riid As Guid, _
         ByRef ppv As IntPtr) As Integer

        <PreserveSig()> _
        Function Clone(ByRef riid As Guid, ByRef ppv As IntPtr) As Integer

        <PreserveSig()> _
        Function GetImageRect(ByVal i As Integer, ByRef prc As RECT) As Integer

        <PreserveSig()> _
        Function GetIconSize(ByRef cx As Integer, ByRef cy As Integer) As Integer

        <PreserveSig()> _
        Function SetIconSize(ByVal cx As Integer, ByVal cy As Integer) As Integer

        <PreserveSig()> _
        Function GetImageCount(ByRef pi As Integer) As Integer

        <PreserveSig()> _
        Function SetImageCount(ByVal uNewCount As Integer) As Integer

        <PreserveSig()> _
        Function SetBkColor(ByVal clrBk As Integer, ByRef pclr As Integer) As Integer

        <PreserveSig()> _
        Function GetBkColor(ByRef pclr As Integer) As Integer

        <PreserveSig()> _
        Function BeginDrag(ByVal iTrack As Integer, ByVal dxHotspot As Integer, ByVal dyHotspot As Integer) As Integer

        <PreserveSig()> _
        Function EndDrag() As Integer

        <PreserveSig()> _
        Function DragEnter(ByVal hwndLock As IntPtr, ByVal x As Integer, ByVal y As Integer) As Integer

        <PreserveSig()> _
        Function DragLeave(ByVal hwndLock As IntPtr) As Integer

        <PreserveSig()> _
        Function DragMove(ByVal x As Integer, ByVal y As Integer) As Integer

        <PreserveSig()> _
        Function SetDragCursorImage(ByRef punk As IImageList, ByVal iDrag As Integer, ByVal dxHotspot As Integer, ByVal dyHotspot As Integer) As Integer

        <PreserveSig()> _
        Function DragShowNolock(ByVal fShow As Integer) As Integer

        <PreserveSig()> _
        Function GetDragImage(ByRef ppt As POINT, ByRef pptHotspot As POINT, ByRef riid As Guid, ByRef ppv As IntPtr) As Integer

        <PreserveSig()> _
        Function GetItemFlags(ByVal i As Integer, ByRef dwFlags As Integer) As Integer

        <PreserveSig()> _
        Function GetOverlayImage(ByVal iOverlay As Integer, ByRef piIndex As Integer) As Integer
    End Interface
#End Region
#End Region

#Region "Properties"
    ''' <summary>
    ''' Gets the hImageList handle
    ''' </summary>
    Public ReadOnly Property Handle() As IntPtr
        Get
            Return Me.hIml
        End Get
    End Property
    ''' <summary>
    ''' Gets/sets the size of System Image List to retrieve.
    ''' </summary>
    Public Property ImageListSize() As SystemImageListSize
        Get
            Return m_size
        End Get
        Set(ByVal value As SystemImageListSize)
            m_size = value
            create()
        End Set
    End Property

    ''' <summary>
    ''' Returns the size of the Image List Icons.
    ''' </summary>
    Public ReadOnly Property Size() As System.Drawing.Size
        Get
            Dim cx As Integer = 0
            Dim cy As Integer = 0

            If kiImageList Is Nothing Then
                ImageList_GetIconSize(hIml, cx, cy)
            Else
                kiImageList.GetIconSize(cx, cy)
            End If

            Dim sz As New System.Drawing.Size(cx, cy)

            Return sz
        End Get
    End Property
#End Region

#Region "Methods"
    ''' <summary>
    ''' Returns a GDI+ copy of the icon from the ImageList
    ''' at the specified index.
    ''' </summary>
    ''' <param name="index">The index to get the icon for</param>
    ''' <returns>The specified icon</returns>
    Public Function Icon(ByVal index As Integer) As Icon
        Dim icon__1 As Icon = Nothing

        Dim hIcon As IntPtr = IntPtr.Zero
        If kiImageList Is Nothing Then

            hIcon = ImageList_GetIcon(hIml, index, CInt(ImageListDrawItemConstants.ILD_TRANSPARENT))
        Else
            kiImageList.GetIcon(index, CInt(ImageListDrawItemConstants.ILD_TRANSPARENT), hIcon)
        End If

        If hIcon <> IntPtr.Zero Then
            icon__1 = System.Drawing.Icon.FromHandle(hIcon)
        End If
        Return icon__1
    End Function

    ''' <summary>
    ''' Return the index of the icon for the specified file, always using 
    ''' the cached version where possible.
    ''' </summary>
    ''' <param name="fileName">Filename to get icon for</param>
    ''' <returns>Index of the icon</returns>
    Public Function IconIndex(ByVal fileName As String) As Integer
        Return IconIndex(fileName, False)
    End Function

    ''' <summary>
    ''' Returns the index of the icon for the specified file
    ''' </summary>
    ''' <param name="fileName">Filename to get icon for</param>
    ''' <param name="forceLoadFromDisk">If True, then hit the disk to get the icon,
    ''' otherwise only hit the disk if no cached icon is available.</param>
    ''' <returns>Index of the icon</returns>
    Public Function IconIndex(ByVal fileName As String, ByVal forceLoadFromDisk As Boolean) As Integer
        Return IconIndex(fileName, forceLoadFromDisk, ShellIconStateConstants.ShellIconStateNormal)
    End Function

    ''' <summary>
    ''' Returns the index of the icon for the specified file
    ''' </summary>
    ''' <param name="fileName">Filename to get icon for</param>
    ''' <param name="forceLoadFromDisk">If True, then hit the disk to get the icon,
    ''' otherwise only hit the disk if no cached icon is available.</param>
    ''' <param name="iconState">Flags specifying the state of the icon
    ''' returned.</param>
    ''' <returns>Index of the icon</returns>
    Public Function IconIndex(ByVal fileName As String, ByVal forceLoadFromDisk As Boolean, ByVal iconState As ShellIconStateConstants) As Integer
        Dim dwFlags As SHGetFileInfoConstants = SHGetFileInfoConstants.SHGFI_SYSICONINDEX
        Dim dwAttr As Integer = 0
        If m_size = SystemImageListSize.SmallIcons Then
            dwFlags = dwFlags Or SHGetFileInfoConstants.SHGFI_SMALLICON
        End If

        ' We can choose whether to access the disk or not. If you don't
        ' hit the disk, you may get the wrong icon if the icon is
        ' not cached. Also only works for files.
        If Not forceLoadFromDisk Then
            dwFlags = dwFlags Or SHGetFileInfoConstants.SHGFI_USEFILEATTRIBUTES
            dwAttr = FILE_ATTRIBUTE_NORMAL
        Else
            dwAttr = 0
        End If

        ' sFileSpec can be any file. You can specify a
        ' file that does not exist and still get the
        ' icon, for example sFileSpec = "C:\PANTS.DOC"
        Dim shfi As New SHFILEINFO()
        Dim shfiSize As UInteger = CUInt(Marshal.SizeOf(shfi.[GetType]()))
        Dim retVal As IntPtr = SHGetFileInfo(fileName, dwAttr, shfi, shfiSize, (CUInt(dwFlags) Or CUInt(iconState)))

        If retVal.Equals(IntPtr.Zero) Then
            System.Diagnostics.Debug.Assert((Not retVal.Equals(IntPtr.Zero)), "Failed to get icon index")
            Return 0
        Else
            Return shfi.iIcon
        End If
    End Function

    ''' <summary>
    ''' Draws an image
    ''' </summary>
    ''' <param name="hdc">Device context to draw to</param>
    ''' <param name="index">Index of image to draw</param>
    ''' <param name="x">X Position to draw at</param>
    ''' <param name="y">Y Position to draw at</param>
    Public Sub DrawImage(ByVal hdc As IntPtr, ByVal index As Integer, ByVal x As Integer, ByVal y As Integer)
        DrawImage(hdc, index, x, y, ImageListDrawItemConstants.ILD_TRANSPARENT)
    End Sub

    ''' <summary>
    ''' Draws an image using the specified flags
    ''' </summary>
    ''' <param name="hdc">Device context to draw to</param>
    ''' <param name="index">Index of image to draw</param>
    ''' <param name="x">X Position to draw at</param>
    ''' <param name="y">Y Position to draw at</param>
    ''' <param name="flags">Drawing flags</param>
    Public Sub DrawImage(ByVal hdc As IntPtr, ByVal index As Integer, ByVal x As Integer, ByVal y As Integer, ByVal flags As ImageListDrawItemConstants)
        If kiImageList Is Nothing Then
            Dim ret As Integer = ImageList_Draw(hIml, index, hdc, x, y, CInt(flags))
        Else
            Dim pimldp As New IMAGELISTDRAWPARAMS()
            pimldp.hdcDst = hdc
            pimldp.cbSize = Marshal.SizeOf(pimldp.[GetType]())
            pimldp.i = index
            pimldp.x = x
            pimldp.y = y
            pimldp.rgbFg = -1
            pimldp.fStyle = CInt(flags)
            kiImageList.Draw(pimldp)
        End If

    End Sub

    ''' <summary>
    ''' Draws an image using the specified flags and specifies
    ''' the size to clip to (or to stretch to if ILD_SCALE
    ''' is provided).
    ''' </summary>
    ''' <param name="hdc">Device context to draw to</param>
    ''' <param name="index">Index of image to draw</param>
    ''' <param name="x">X Position to draw at</param>
    ''' <param name="y">Y Position to draw at</param>
    ''' <param name="flags">Drawing flags</param>
    ''' <param name="cx">Width to draw</param>
    ''' <param name="cy">Height to draw</param>
    Public Sub DrawImage(ByVal hdc As IntPtr, ByVal index As Integer, ByVal x As Integer, ByVal y As Integer, ByVal flags As ImageListDrawItemConstants, ByVal cx As Integer, _
     ByVal cy As Integer)
        Dim pimldp As New IMAGELISTDRAWPARAMS()
        pimldp.hdcDst = hdc
        pimldp.cbSize = Marshal.SizeOf(pimldp.[GetType]())
        pimldp.i = index
        pimldp.x = x
        pimldp.y = y
        pimldp.cx = cx
        pimldp.cy = cy
        pimldp.fStyle = CInt(flags)
        If kiImageList Is Nothing Then
            pimldp.himl = hIml
            Dim ret As Integer = ImageList_DrawIndirect(pimldp)
        Else

            kiImageList.Draw(pimldp)
        End If
    End Sub

    ''' <summary>
    ''' Draws an image using the specified flags and state on XP systems.
    ''' </summary>
    ''' <param name="hdc">Device context to draw to</param>
    ''' <param name="index">Index of image to draw</param>
    ''' <param name="x">X Position to draw at</param>
    ''' <param name="y">Y Position to draw at</param>
    ''' <param name="flags">Drawing flags</param>
    ''' <param name="cx">Width to draw</param>
    ''' <param name="cy">Height to draw</param>
    ''' <param name="foreColor">Fore colour to blend with when using the 
    ''' ILD_SELECTED or ILD_BLEND25 flags</param>
    ''' <param name="stateFlags">State flags</param>
    ''' <param name="glowOrShadowColor">If stateFlags include ILS_GLOW, then
    ''' the colour to use for the glow effect.  Otherwise if stateFlags includes 
    ''' ILS_SHADOW, then the colour to use for the shadow.</param>
    ''' <param name="saturateColorOrAlpha">If stateFlags includes ILS_ALPHA,
    ''' then the alpha component is applied to the icon. Otherwise if 
    ''' ILS_SATURATE is included, then the (R,G,B) components are used
    ''' to saturate the image.</param>
    Public Sub DrawImage(ByVal hdc As IntPtr, ByVal index As Integer, ByVal x As Integer, ByVal y As Integer, ByVal flags As ImageListDrawItemConstants, ByVal cx As Integer, _
     ByVal cy As Integer, ByVal foreColor As System.Drawing.Color, ByVal stateFlags As ImageListDrawStateConstants, ByVal saturateColorOrAlpha As System.Drawing.Color, ByVal glowOrShadowColor As System.Drawing.Color)
        Dim pimldp As New IMAGELISTDRAWPARAMS()
        pimldp.hdcDst = hdc
        pimldp.cbSize = Marshal.SizeOf(pimldp.[GetType]())
        pimldp.i = index
        pimldp.x = x
        pimldp.y = y
        pimldp.cx = cx
        pimldp.cy = cy
        pimldp.rgbFg = Color.FromArgb(0, foreColor.R, foreColor.G, foreColor.B).ToArgb()
        '			Console.WriteLine("{0}", pimldp.rgbFg);
        pimldp.fStyle = CInt(flags)
        pimldp.fState = CInt(stateFlags)
        If (stateFlags And ImageListDrawStateConstants.ILS_ALPHA) = ImageListDrawStateConstants.ILS_ALPHA Then
            ' Set the alpha:
            pimldp.Frame = CInt(saturateColorOrAlpha.A)
        ElseIf (stateFlags And ImageListDrawStateConstants.ILS_SATURATE) = ImageListDrawStateConstants.ILS_SATURATE Then
            ' discard alpha channel:
            saturateColorOrAlpha = Color.FromArgb(0, saturateColorOrAlpha.R, saturateColorOrAlpha.G, saturateColorOrAlpha.B)
            ' set the saturate color
            pimldp.Frame = saturateColorOrAlpha.ToArgb()
        End If
        glowOrShadowColor = Color.FromArgb(0, glowOrShadowColor.R, glowOrShadowColor.G, glowOrShadowColor.B)
        pimldp.crEffect = glowOrShadowColor.ToArgb()
        If kiImageList Is Nothing Then
            pimldp.himl = hIml
            Dim ret As Integer = ImageList_DrawIndirect(pimldp)
        Else

            kiImageList.Draw(pimldp)
        End If
    End Sub
#End Region
End Class

#End Region

#Region "SystemImageListHelper class"
''' <summary>
''' Helper Methods for Connecting SystemImageList to Common Controls
''' </summary>
Public Class SystemImageListHelper
#Region "Constants"
    Private Const LVM_FIRST As Integer = &H1000
    Private Const LVM_SETIMAGELIST As Integer = (LVM_FIRST + 3)

    Private Const LVSIL_NORMAL As Integer = 0
    Private Const LVSIL_SMALL As Integer = 1
    Private Const LVSIL_STATE As Integer = 2

    Private Const TV_FIRST As Integer = &H1100
    Private Const TVM_SETIMAGELIST As Integer = (TV_FIRST + 9)

    Private Const TVSIL_NORMAL As Integer = 0
    Private Const TVSIL_STATE As Integer = 2
#End Region

#Region "Implementation"
    <DllImport("user32", CharSet:=CharSet.Auto)> _
    Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
    End Function
#End Region

#Region "Methods"
    ''' <summary>
    ''' Associates a SysImageList with a ListView control
    ''' </summary>
    ''' <param name="listView">ListView control to associate ImageList with</param>
    ''' <param name="sysImageList">System Image List to associate</param>
    ''' <param name="forStateImages">Whether to add ImageList as StateImageList</param>
    Public Shared Sub SetListViewImageList(ByVal listView As ListView, ByVal sysImageList As SystemImageList, ByVal forStateImages As Boolean)
        Dim wParam As IntPtr = CType(LVSIL_NORMAL, IntPtr)
        If sysImageList.ImageListSize = SystemImageListSize.SmallIcons Then
            wParam = CType(LVSIL_SMALL, IntPtr)
        End If
        If forStateImages Then
            wParam = CType(LVSIL_STATE, IntPtr)
        End If
        SendMessage(listView.Handle, LVM_SETIMAGELIST, wParam, sysImageList.Handle)
    End Sub

    ''' <summary>
    ''' Associates a SysImageList with a TreeView control
    ''' </summary>
    ''' <param name="treeView">TreeView control to associated ImageList with</param>
    ''' <param name="sysImageList">System Image List to associate</param>
    ''' <param name="forStateImages">Whether to add ImageList as StateImageList</param>
    Public Shared Sub SetTreeViewImageList(ByVal treeView As TreeView, ByVal sysImageList As SystemImageList, ByVal forStateImages As Boolean)
        Dim wParam As IntPtr = CType(TVSIL_NORMAL, IntPtr)
        If forStateImages Then
            wParam = CType(TVSIL_STATE, IntPtr)
        End If
        SendMessage(treeView.Handle, TVM_SETIMAGELIST, wParam, sysImageList.Handle)
    End Sub

#End Region
End Class
#End Region